/********************************************
 * 功能说明: 
 * 模块名称: 
 * 系统名称: 
 * 软件版权: Frank
 * 系统版本: 1.0.0
 * 开发人员: Frank
 * 开发时间: 2019/12/30 14:01
 * 审核人员: 
 * 相关文档: 
 * 修改记录: 修改日期 修改人员 修改说明
 *********************************************/
package com.spring.arch.uaa.web.converter;

import com.spring.arch.uaa.dto.*;
import com.spring.arch.uaa.enums.ClientType;
import com.spring.arch.uaa.enums.ProjectStatus;
import com.spring.arch.uaa.enums.TenantStatus;
import com.spring.arch.uaa.errorcode.UaaErrorCode;
import com.spring.arch.common.exception.ExceptionHolder;
import com.spring.arch.uaa.bean.UserClientBean;
import com.spring.arch.uaa.dto.*;
import com.spring.arch.uaa.enums.ClientType;
import com.spring.arch.uaa.enums.Constant;
import com.spring.arch.uaa.enums.ProjectStatus;
import com.spring.arch.uaa.enums.TenantStatus;
import com.spring.arch.uaa.model.*;
import com.spring.arch.uaa.oauth2.service.OauthUserDetailsServiceImpl;
import com.spring.arch.uaa.repository.OrganizationEmployeeRepository;
import com.spring.arch.uaa.repository.OrganizationEmployeeRoleRepository;
import lombok.NonNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;

import static com.spring.arch.uaa.errorcode.UaaErrorCode.E2001005002;

/**
 * 用户客户端信息转换器
 *
 * @author Frank
 * @version 1.0.0.1
 * @since 2019/12/30 14:01
 */
@Component
public class UserClientConverter {

    @Autowired
    private AuthorityConverter authorityConverter;

    @Autowired
    private OauthUserDetailsServiceImpl userDetailsService;
    @Autowired
    private OrganizationEmployeeRepository organizationEmployeeRepository;
    @Autowired
    private OrganizationEmployeeRoleRepository organizationEmployeeRoleRepository;

    /**
     * 根据token中的载荷信息加载用户信息
     *
     * @param username 用户名
     * @param clientId
     * @return 用户DTO
     */
    public Set<ClientDTO> loadClients(String username, String clientId) {
        User user = userDetailsService.loadUserByMobileOrUserName(username);
        Set<ClientDTO> clients = new HashSet<>();
        // 加载用户客户端信息
        List<OrganizationEmployee> organizationEmployees = organizationEmployeeRepository.findByUserAndStatusTrue(user);
        if (!CollectionUtils.isEmpty(organizationEmployees)) {
            organizationEmployees.forEach(e -> {
                List<OrganizationEmployeeRole> employeeRoles = organizationEmployeeRoleRepository.findByOrganizationEmployee(e);
                if (!CollectionUtils.isEmpty(employeeRoles)) {
                    employeeRoles.forEach(r -> {
                        // clients
                        clients.addAll(this.toClientDTO(r, clientId));
                    });
                }
            });
        }
        if (CollectionUtils.isEmpty(clients)) {
            throw ExceptionHolder.serviceException(UaaErrorCode.E2001005002);
        }

        return clients;
    }

    private List<ClientDTO> toClientDTO(OrganizationEmployeeRole model, String clientId) {
        List<ClientDTO> clients = new ArrayList<>(3);
        if (Constant.OAUTH_CLIENT_ID_WEB.equalsIgnoreCase(clientId)) {
            // 超级管理员权限
            @NotNull Role role = model.getRole();
            if (Constant.SUPER_ADMIN_ROLE_CODE.equalsIgnoreCase(role.getCode())) {
                ClientDTO dto = new ClientDTO();
                dto.setId(UUID.fromString(Constant.SAAS_MANAGER_CENTER_ID));
                dto.setClientType(ClientType.MANAGER);
                dto.setName("系统管理端");
                clients.add(dto);
            }
            Tenant tenant = model.getTenant();
            if (tenant != null
                    && !TenantStatus.DISCARDED.equals(tenant.getStatus())
                    && !tenant.isDisable()
                    && !tenant.getCode().equalsIgnoreCase(Constant.INTERNAL_TENANT_CODE)
                    && Constant.TENANT_ADMIN_ROLE_CODE.equals(role.getCode())) {
                ClientDTO dto = new ClientDTO();
                dto.setId(tenant.getId());
                dto.setClientType(ClientType.TENANT);
                dto.setName(tenant.getName());
                clients.add(dto);
            }
        }
        Project project = model.getProject();
        if (project != null
                && !ProjectStatus.OFFLINE.equals(project.getStatus())
                && !ProjectStatus.FAILURE.equals(project.getStatus())) {
            ClientDTO dto = new ClientDTO();
            dto.setId(project.getId());
            dto.setClientType(ClientType.PROJECT);
            dto.setName(model.getProject().getName());
            clients.add(dto);
        }
        return clients;
    }

    public UserDTO toDTO(UserClientBean model, String scopeId) {
        UserDTO dto = new UserDTO();
        dto.setClientId(model.getClientId());
        dto.setUserPrincipal(model.getUserPrincipal());

        if (Constant.OAUTH_CLIENT_ID_WEB.equalsIgnoreCase(scopeId)) {
            if (model.getTenant() != null) {
                dto.setTenant(this.toTenantDTO(model.getTenant()));
            }

            if (model.getProject() != null) {
                dto.setProject(this.toProjectDTO(model.getProject()));
            }

            if (model.getRootOrganization() != null) {
                dto.setRootOrganization(this.toOrganizationDTO(model.getRootOrganization()));
            }

            Set<Organization> organizations = model.getOrganizations();
            if (!CollectionUtils.isEmpty(organizations)) {
                dto.setOrganizations(organizations.stream().map(this::toOrganizationDTO).collect(Collectors.toSet()));
            }

            Set<TenantEmployee> employees = model.getEmployees();
            if (!CollectionUtils.isEmpty(employees)) {
                dto.setEmployees(employees.stream().map(this::toEmployeeDTO).collect(Collectors.toSet()));
            }

            Set<Role> roles = model.getRoles();
            if (!CollectionUtils.isEmpty(roles)) {
                dto.setRoles(roles.stream().map(this::toRoleDTO).collect(Collectors.toSet()));
            }

            Set<Authority> authorities = model.getAuthorities();
            if (!CollectionUtils.isEmpty(authorities)) {
                List<AuthorityDTO> res = authorityConverter.toTree(authorities);
                dto.setAuthorities(new HashSet<>(res));
            }
        }

        return dto;
    }

    private RoleDTO toRoleDTO(Role model) {
        RoleDTO dto = new RoleDTO();
        dto.setId(model.getId());
        dto.setCode(model.getCode());
        dto.setTenantId(model.getTenant() == null ? null : model.getTenant().getId());
        dto.setName(model.getName());
        return dto;
    }

    private OrganizationDTO toOrganizationDTO(Organization model) {
        OrganizationDTO dto = new OrganizationDTO();
        dto.setId(model.getId());
        dto.setTenantId(model.getTenant().getId());
        dto.setParentId(model.getParent() == null ? null : model.getParent().getId());
        dto.setProjectId(model.getProject() == null ? null : model.getProject().getId());
        dto.setCode(model.getCode());
        dto.setName(model.getName());
        dto.setType(model.getType());
        return dto;
    }

    private EmployeeDTO toEmployeeDTO(TenantEmployee model) {
        EmployeeDTO dto = new EmployeeDTO();
        dto.setId(model.getId());
        dto.setCode(model.getCode());
        dto.setName(model.getName());
        dto.setMobile(model.getMobile());
        dto.setGender(model.getGender());
        dto.setEmail(model.getEmail());
        dto.setPhotos(model.getPhotos());
        return dto;
    }

    private TenantDTO toTenantDTO(@NonNull final Tenant model) {
        final TenantDTO dto = new TenantDTO();
        dto.setCode(model.getCode());
        dto.setName(model.getName());
        dto.setAbbreviation(model.getAbbreviation());
        dto.setContact(model.getContact());
        dto.setMobile(model.getMobile());
        dto.setDomain(model.getDomain());
        dto.setDomainIdentity(model.getDomainIdentity());
        dto.setLogo(model.getLogo());
        dto.setStatus(model.getStatus());
        return dto;
    }

    private ProjectDTO toProjectDTO(@NonNull final Project model) {
        final ProjectDTO dto = new ProjectDTO();

        dto.setId(model.getId());
        dto.setCode(model.getCode());
        dto.setName(model.getName());
        dto.setType(model.getType());
        dto.setTypeName(model.getType().getCode());
        dto.setAreaId(model.getAreaId());
        dto.setAddress(model.getAddress());
        dto.setRemarks(model.getRemarks());
        dto.setStatus(model.getStatus());
        dto.setRootOrganizationId(model.getRootOrganization().getId());
        dto.setDatasourceId(model.getDatasource().getId());
        dto.setTenantId(model.getTenant().getId());

        return dto;
    }
}
